package net.doglog;

import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.JspWriter;

import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;

import java.net.URLDecoder;

public final class BlogUtil {
	public static String attribute(HttpServletRequest req, String name) {
		String value = (String) req.getAttribute(name);
		if (value == null) value = "";
		return value.trim();
	}

	public static String escapeTag(String s) {
		return s.replace("&", "&amp;")
				.replace("<", "&lt;")
				.replace(">", "&gt;");
	}
	
	public static String escapeLine(String s) {
		return s.replace("\r\n", "<br/>")
				.replace("\n\r", "<br/>")
				.replace("\r", "<br/>")
				.replace("\n", "<br/>");
	}
	
	public static String escapeAll(String s) {
		return escapeLine(escapeTag(s));
	}
	
	public static long parseId(String pathInfo) {
		int id = 0;
		if (pathInfo != null && pathInfo.matches("/\\d{1,4}"))
			id = Integer.valueOf(pathInfo.substring(1));
		return id;
	}
	
	public static String parseName(String pathInfo) {
		String name = "";
		if (pathInfo != null)
			try {
				name = URLDecoder.decode(pathInfo.substring(1), "UTF-8");
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			}
		assert name != null;
		return name;
	}
	
	public static int parsePageNumber(String param) {
		int pageNumber = 1;
		if (param != null && param.matches("\\d{1,4}"))
			pageNumber = Integer.valueOf(param);
		return pageNumber;
	}
	
	public static int calcTotalPages(int totalCount, int perPage) {
		int totalPages = totalCount / perPage;
		if (totalCount % perPage != 0)
			totalPages++;
		return totalPages;
	}
	
	public static void showPosts(List<Post> posts, HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		int pageNumber = parsePageNumber(req.getParameter("page"));
		
		int totalPosts = posts.size();
		int totalPages = calcTotalPages(totalPosts, Blog.postPerPage);
		
		int fromIndex = Math.min(Blog.postPerPage * (pageNumber-1), totalPosts);
		int toIndex = Math.min(fromIndex + Blog.postPerPage, totalPosts);
		
		boolean hasPrevPage = 1 < pageNumber && pageNumber <= totalPages;
		boolean hasNextPage = 1 <= pageNumber && pageNumber < totalPages;
		
		req.setAttribute("posts", posts.subList(fromIndex, toIndex));
		req.setAttribute("hasPrevPage", hasPrevPage);
		req.setAttribute("hasNextPage", hasNextPage);
		req.getRequestDispatcher("/posts.jsp").forward(req, resp);
	}
	
	public static void printError(JspWriter out, String message) throws IOException {
		out.println("<span class=\"error\">" + message + "</span>");
	}
	
	public static String listComments(List<Comment> comments, Key parentKey) throws IOException {
		StringBuilder sb = new StringBuilder();
		for (Comment c : comments)
			if (matchKeys(c.getParentKey(), parentKey)) {
				if (c.getSpeaker().equals(Blog.author))
					sb.append("<dt class=\"highlight\">");
				else sb.append("<dt>");
				sb.append("<a class=\"anchor\"" +
						" name=\"" + c.getId() + "\"" +
						" href=\"/post/" + c.getAncestorKey().getId() + "#" + c.getId() + "\"" +
						">#</a>" +
						"<a href=\"javascript:void reply('" +
						KeyFactory.keyToString(c.getKey()) + "', '" +
						c.getSpeaker() + "');\"" +
						">" + c.getSpeaker() + "</a>" +
						"</dt>");
				sb.append("<dd class=\"time\">" + PostUtil.formatTime(c.getTime()) + "</dd>");
				sb.append("<dd class=\"content\">" + c.getContent() + "</dd>");
				String children = listComments(comments, c.getKey()).trim();
				if (children.length() > 0) {
					sb.append("<dd class=\"replies\">");
					sb.append(children);
					sb.append("</dd>");
				}
			}
		String str = sb.toString().trim();
		if (str.length() > 0) str = "<dl>" + str + "</dl>";
		return str;
	}

	private static boolean matchKeys(Key k1, Key k2) {
		if (k1 == null && k2 == null) return true;
		else if (k1 == null) return false;
		else return k1.equals(k2);
	}
}
